//  Copyright (c) 2012-2013, Jordi Corbilla
//  All rights reserved.
//
//  Redistribution and use in source and binary forms, with or without
//  modification, are permitted provided that the following conditions are met:
//
//  - Redistributions of source code must retain the above copyright notice,
//    this list of conditions and the following disclaimer.
//  - Redistributions in binary form must reproduce the above copyright notice,
//    this list of conditions and the following disclaimer in the documentation
//    and/or other materials provided with the distribution.
//  - Neither the name of this library nor the names of its contributors may be
//    used to endorse or promote products derived from this software without
//    specific prior written permission.
//
//  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
//  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
//  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
//  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
//  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
//  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
//  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
//  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
//  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
//  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
//  POSSIBILITY OF SUCH DAMAGE.

unit Testthundax.UMLDiagrams;
{

  Delphi DUnit Test Case
  ----------------------
  This unit contains a skeleton test case class generated by the Test Case Wizard.
  Modify the generated code to correctly setup and call the methods from the unit 
  being tested.

}

interface

uses
  TestFramework, thundax.UML, thundax.logging;

type
  // Test methods for class TUML

  TestTUML = class(TTestCase)
  strict private
    FUML: TUML;
    FUmlFileName: string;
  public
    procedure SetUp; override;
    procedure TearDown; override;
  published
    procedure TestUMLDiagram;
    procedure TestUMLDiagramExtended;
    procedure TestUMLDiagramAsynchronous;
  end;

implementation

uses
  SysUtils, Windows, SyncObjs, Classes, Diagnostics;

procedure TestTUML.SetUp;
begin
  FUmlFileName := 'TestDiagramUML';
  FUML := TUML.Start(FUmlFileName);
end;

procedure TestTUML.TearDown;
begin
  FUML.Free;
  FUML := nil;
end;

procedure TestTUML.TestUMLDiagram;
begin
  //Example Calling different imaginary methods
  if fileExists(FUmlFileName + '.sdx') then
    DeleteFile(PChar(FUmlFileName + '.sdx'));

  if fileExists(FUmlFileName + '.jpg') then
    DeleteFile(PChar(FUmlFileName + '.jpg'));

  FUML.Define('Server', 'TServer');
  FUML.Define('Proxy', 'TProxy');
  FUML.Define('Client1', 'TClient');
  FUML.Define('Client2', 'TClient');
  FUML.Define('Client3', 'TClient');
  FUML.Define();

  FUML.Call('Server','Proxy','start','');
  FUML.Call('Proxy','Client1','start','', 'STARTED');
  FUML.Call('Proxy','Client2','start','', 'STARTED');
  FUML.Call('Proxy','Client3','start','', 'STARTED');
  //Generating the diagram
  FUML.Convert;
  Sleep(2000); //give time the file to be generated
  CheckTrue(FileExists(FUmlFileName + '.jpg'), 'Error, File was not created');
end;

procedure TestTUML.TestUMLDiagramAsynchronous;
var
  lock: TCriticalSection;
  thread1, thread2, thread3: TThread;
  sw : TStopWatch;
begin
  //Example Calling different imaginary methods
  if fileExists(FUmlFileName + '.sdx') then
    DeleteFile(PChar(FUmlFileName + '.sdx'));

  if fileExists(FUmlFileName + '.jpg') then
    DeleteFile(PChar(FUmlFileName + '.jpg'));

  lock := TCriticalSection.Create;
  FUML.Define('Application', 'TApplication');
  FUML.Define('MainThread', 'TThread');
  FUML.Define('thread1', 'TThread');
  FUML.Define('thread2', 'TThread');
  FUML.Define('thread3', 'TThread');
  FUML.Define();

  FUML.Call('Application','MainThread','Start','');

  thread1 := TThread.CreateAnonymousThread( procedure
  var
    b : Boolean;
    i : integer;
    j : Integer;
  begin
    thread1.NameThreadForDebugging('thread1a');
    b := True;
    i := 0;
    lock.Acquire;
    sw := TStopWatch.StartNew;
    j := 10 + Random(300);
    while b do
    begin
      inc(i);
      b:= (i < j);
      sleep(10);
    end;
    FUML.Call('MainThread','thread1','CreateAnonymousThread',IntToStr(j), 'DONE(' + IntToStr(sw.ElapsedMilliseconds) + 'ms)');
    lock.Release;
  end);
  thread1.FreeOnTerminate := false;
  thread1.Start;

  thread2 := TThread.CreateAnonymousThread( procedure
  var
    b : Boolean;
    i : integer;
    j : Integer;
  begin
    thread2.NameThreadForDebugging('thread2a');
    b := True;
    i := 0;
    lock.Acquire;
    sw := TStopWatch.StartNew;
    j := 10 + Random(300);
    while b do
    begin
      inc(i);
      b:= (i < j);
      sleep(10);
    end;
    FUML.Call('MainThread','thread2','CreateAnonymousThread',IntToStr(j), 'DONE(' + IntToStr(sw.ElapsedMilliseconds) + 'ms)');
    lock.Release;
  end);
  thread2.FreeOnTerminate := false;
  thread2.Start;

  thread3 := TThread.CreateAnonymousThread( procedure
  var
    b : Boolean;
    i : integer;
    j : Integer;
  begin
    thread3.NameThreadForDebugging('thread3a');
    b := True;
    i := 0;
    lock.Acquire;
    sw := TStopWatch.StartNew;
    j := 10 + Random(300);
    while b do
    begin
      inc(i);
      b:= (i < j);
      sleep(10);
    end;
    FUML.Call('MainThread','thread3','CreateAnonymousThread',IntToStr(j), 'DONE(' + IntToStr(sw.ElapsedMilliseconds) + 'ms)');
    lock.Release;
  end);

  thread3.FreeOnTerminate := false;
  thread3.Start;

  thread1.WaitFor;
  thread2.WaitFor;
  thread3.WaitFor;
  thread1.Terminate;
  thread1.Free;
  thread2.Terminate;
  thread2.Free;
  thread3.Terminate;
  thread3.Free;
  //Generating the diagram
  FUML.Convert;
  Sleep(2000); //give time the file to be generated
  CheckTrue(FileExists(FUmlFileName + '.jpg'), 'Error, File was not created');
  lock.Free;
end;

procedure TestTUML.TestUMLDiagramExtended;
begin
  //Example Calling different imaginary methods
  if fileExists(FUmlFileName + '.sdx') then
    DeleteFile(PChar(FUmlFileName + '.sdx'));

  if fileExists(FUmlFileName + '.jpg') then
    DeleteFile(PChar(FUmlFileName + '.jpg'));

  FUML.Define('Server', 'TServer');
  FUML.Define('Proxy', 'TProxy');
  FUML.Define('Client1', 'TClient');
  FUML.Define('Client2', 'TClient');
  FUML.Define('Client3', 'TClient');
  FUML.Define('Client4', 'TClient');
  FUML.Define('Client5', 'TClient');
  FUML.Define('Client6', 'TClient');
  FUML.Define('Client7', 'TClient');
  FUML.Define('Client8', 'TClient');
  FUML.Define();

  FUML.Call('Server','Proxy','start','');
  FUML.Call('Proxy','Client1','start','200', 'STARTED');
  FUML.Call('Proxy','Client2','start','200', 'STARTED');
  FUML.Call('Proxy','Client3','start','200', 'DOWN');
  FUML.Call('Proxy','Client4','start','200', 'STARTED');
  FUML.Call('Proxy','Client5','start','200', 'STARTED');
  FUML.Call('Proxy','Client6','start','200', 'STARTED');
  FUML.Call('Proxy','Client7','start','200', 'DOWN');
  FUML.Call('Proxy','Client8','start','200', 'DOWN');

  FUML.Call('Proxy','Proxy','RemoveDown','');
  FUML.Call('Proxy','Client3','Detach', '', 'DETACHED');
  FUML.Call('Proxy','Client7','Detach', '', 'DETACHED');
  FUML.Call('Proxy','Client8','Detach', '', 'DETACHED');
  //Generating the diagram
  FUML.Convert;
  Sleep(2000); //give time the file to be generated
  CheckTrue(FileExists(FUmlFileName + '.jpg'), 'Error, File was not created');
end;

initialization
  RegisterTest(TestTUML.Suite);
end.

